/*************************************************
Copyright (C), 2018-2028, Crise Tech. Co., Ltd.
File name: task.cpp
Author: rise0chen
Version: 1.0
Date: 2019.08.30
Description: task定时任务
Usage:
  #include "task.h"
  task_init(100); //设置心跳间隔
  task_add(0x01, myTest, 10000 / task_oneTime); // 新建任务 10秒1次
  task_start(0x01, 0xFFFF, 0, 0xFFFF);  // 启动任务 执行无限次
  task_run(); //执行任务(必须放在loop大循环里) History: rise0chen
2019.08.30   抽象成常用函数
*************************************************/
#include "task.h"

LinkedListStruct* linkedList_tasks = NULL;
uint16_t task_oneTime = 0;  // 1次系统心跳的时间(ms)
uint32_t task_times = 0;    //系统心跳次数

/*************************************************
Function: task_init
Description: 初始化心跳间隔
Input: nms 心跳间隔 单位ms
Return: void
*************************************************/
void task_init(uint16_t nms) {
  mempool_init(0x400);
  if (linkedList_tasks == NULL) {
    linkedList_tasks = linkedList_new();
  }
  task_oneTime = nms;
}

/*************************************************
Function: task_find
Description: 根据uid查找任务结构体
Input:
        uid    任务编码 0~0xFFFF
Return: void
*************************************************/
static Task_Struct* task_find(uint16_t uid) {
  Task_Struct* task;

  linkedList_tasks->current = linkedList_tasks->first;
  while (linkedList_tasks->current != NULL) {
    task = (Task_Struct*)linkedList_tasks->current->data;
    if (task->uid == uid) {
      return task;
    }
    linkedList_tasks->current = linkedList_tasks->current->next;
  }
  return NULL;
}

/*************************************************
Function: task_add
Description: 新建任务
Input:
        uid  任务编码 0~0xFFFF
        func 需要执行的函数
        in   几次系统心跳执行一次(1)   0每次loop循环都执行
Return: void
*************************************************/
void task_add(uint16_t uid, void (*func)(void), uint16_t in) {
  Task_Struct* task;
  task = task_find(uid);
  if (task == NULL) {
    task = (Task_Struct*)mempool_alloc(sizeof(Task_Struct));
  }
  task->uid = uid;
  task->status = taskStatus_error;
  task->func = func;
  task->interval = in;

  linkedList_addData(linkedList_tasks, task);
}

/*************************************************
Function: task_start
Description: 开始任务
Input:
        uid    任务编码 0~0xFFFF
        ts   最多执行几次(0xFFFF)   0永不执行 0xFFFF无限次
        st   几次系统心跳后开始执行(0) 0立即执行
        et   几次系统心跳后结束执行(0xFFFF) 0永不执行 0xFFFF永不停止
Return: void
*************************************************/
void task_start(uint16_t uid, uint16_t ts, uint16_t st, uint16_t et) {
  Task_Struct* task;
  task = task_find(uid);
  if (task) {
    task->status = taskStatus_ready;
    task->startTime = task_times + st;
    if (et == 0xFFFF) {
      task->endTime = 0xFFFFFFFF;
    } else {
      task->endTime = task_times + et;
    }
    task->times = ts;
    task->timesRun = 0;
  }
}

/*************************************************
Function: task_stop
Description: 停止任务
Input:
        uid    任务编码 0~0xFFFF
Return: void
*************************************************/
void task_stop(uint16_t uid) {
  Task_Struct* task;
  task = task_find(uid);
  if (task) {
    task->status = taskStatus_stop;
  }
}

/*************************************************
Function: task_cmd
Description: 控制任务状态
Input:
        uid    任务编码 0~0xFFFF
        status 状态
Return: void
*************************************************/
void task_cmd(uint16_t uid, Task_Status status) {
  Task_Struct* task;
  task = task_find(uid);
  if (task) {
    task->status = status;
  }
}

/*************************************************
Function: task_tick
Description: 一次心跳
Input: void
Return: void
*************************************************/
void task_tick(void) {
  task_times++;
  Task_Struct* task;
  LinkedListUnitStruct* current;

  current = linkedList_tasks->first;
  while (current != NULL) {
    task = (Task_Struct*)current->data;
    if (task->status == taskStatus_ready || task->status == taskStatus_finish) {
      if ((task_times >= task->startTime) && (task_times < task->endTime)) {
        if (task->times == 0xFFFF || task->timesRun < task->times) {
          if (task->interval == 0) {
            task->status = taskStatus_run;
          } else if ((task_times - task->startTime) % task->interval == 0) {
            task->status = taskStatus_run;
          }
        }
      }
    }
    current = current->next;
  }
}

/*************************************************
Function: task_run
Description: 执行任务
Input: void
Return: void
*************************************************/
void task_run(void) {
  Task_Struct* task;
  LinkedListUnitStruct* current;

  current = linkedList_tasks->first;
  while (current != NULL) {
    task = (Task_Struct*)current->data;
    if (task->status == taskStatus_run) {
      if (task->interval == 0) {
        if ((task_times >= task->startTime) && (task_times < task->endTime)) {
          if (task->times == 0xFFFF || task->timesRun < task->times) {
            task->timesRun++;
            task->func();
          }
        }
      } else {
        task->timesRun++;
        task->func();
        task->status = taskStatus_finish;
      }
    }
    current = current->next;
  }
}
